using System;
using System.Collections.Generic;
using System.Linq;

namespace MT5Trade.Models
{
    /// <summary>
    /// 破产概率模型核心类
    /// 基于Gambler's Ruin数学模型实现动态杠杆控制
    /// 根据市场波动率和账户状况调整杠杆使用，防止账户爆仓
    /// </summary>
    public class BankruptcyModel
    {
        #region 常量定义

        /// <summary>
        /// 目标破产概率阈值（5%）
        /// </summary>
        public const double TARGET_BANKRUPTCY_PROBABILITY = 0.05;

        /// <summary>
        /// 最大杠杆比例限制
        /// </summary>
        public const double MAX_LEVERAGE_RATIO = 200.0;

        /// <summary>
        /// 最小杠杆比例
        /// </summary>
        public const double MIN_LEVERAGE_RATIO = 10.0;

        /// <summary>
        /// 低波动率阈值
        /// </summary>
        public const double LOW_VOLATILITY_THRESHOLD = 0.01;

        /// <summary>
        /// 中波动率阈值
        /// </summary>
        public const double MEDIUM_VOLATILITY_THRESHOLD = 0.02;

        /// <summary>
        /// 风险厌恶参数λ
        /// </summary>
        public const double RISK_AVERSION_PARAMETER = 0.1;

        /// <summary>
        /// 计算精度要求
        /// </summary>
        public const double CALCULATION_PRECISION = 0.0001;

        #endregion

        #region 核心概率计算方法

        /// <summary>
        /// 计算连续时间破产概率
        /// 使用几何布朗运动模型：P(τ < ∞) = (S_barrier/S_0)^(2μ/σ²)
        /// </summary>
        /// <param name="expectedReturn">期望收益率μ</param>
        /// <param name="volatility">波动率σ</param>
        /// <param name="leverageRatio">杠杆比例L</param>
        /// <param name="initialCapital">初始资金S_0</param>
        /// <returns>破产概率，范围[0,1]</returns>
        /// <exception cref="ArgumentException">参数无效时抛出异常</exception>
        public double CalculateContinuousBankruptcyProbability(double expectedReturn, double volatility, 
            double leverageRatio, double initialCapital = 1.0)
        {
            // 参数验证
            if (volatility <= 0)
                throw new ArgumentException($"波动率{volatility:F6}必须大于0", nameof(volatility));
            
            if (leverageRatio <= 1.0)
                throw new ArgumentException($"杠杆比例{leverageRatio:F2}必须大于1", nameof(leverageRatio));
            
            if (initialCapital <= 0)
                throw new ArgumentException("初始资金必须大于0", nameof(initialCapital));

            // 期望收益率验证
            if (expectedReturn <= 0)
                throw new ArgumentException($"期望收益率{expectedReturn:F6}必须大于0", nameof(expectedReturn));

            // 计算破产边界：S_barrier = S_0 × (1 - 1/L)
            double bankruptcyBarrier = initialCapital * (1.0 - 1.0 / leverageRatio);
            
            if (bankruptcyBarrier <= 0)
                return 1.0; // 边界无效，必然破产
            
            // 使用标准的几何布朗运动首达时间概率公式
            // P = exp(-2(μ - σ²/2) * log(S_0/barrier) / σ²)
            double probabilityRatio = bankruptcyBarrier / initialCapital;
            
            // 处理边界情况
            if (probabilityRatio >= 1.0)
                return 0.0; // 无破产边界
            
            if (probabilityRatio <= 0)
                return 1.0; // 立即破产
            
            // 修正期望收益率：μ_adj = μ - σ²/2（由于几何布朗运动的漂移修正）
            double adjustedDrift = expectedReturn - (volatility * volatility) / 2.0;
            
            // 当修正漂移为负或接近0时，破产概率很高
            if (adjustedDrift <= 0)
            {
                // 使用简化公式：P = barrier/S_0（当μ = σ²/2时的特殊情况）
                return 1.0 - probabilityRatio; // 1 - barrier/S_0 = 破产概率
            }
            
            // 计算破产概率：P = (S_barrier/S_0)^(2μ/σ²) 当S_0 > S_barrier时
            // 注意：当初始资金大于破产边界时，使用正确的公式
            double powerExponent = (2 * adjustedDrift) / (volatility * volatility);
            double bankruptcyProbability = Math.Pow(bankruptcyBarrier / initialCapital, powerExponent);
            
            // 确保概率在有效范围内
            return Math.Max(0.0, Math.Min(1.0, bankruptcyProbability));
        }

        /// <summary>
        /// 计算离散时间Gambler's Ruin破产概率
        /// P = ((q/p)^a - (q/p)^N) / (1 - (q/p)^N)，当p ≠ q时
        /// </summary>
        /// <param name="winRate">胜率p</param>
        /// <param name="oddsRatio">赔率b</param>
        /// <param name="currentCapital">当前资金a</param>
        /// <param name="maxCapital">资金上限N</param>
        /// <returns>破产概率，范围[0,1]</returns>
        public double CalculateDiscreteGamblersRuin(double winRate, double oddsRatio, 
            int currentCapital, int maxCapital)
        {
            // 参数验证
            if (winRate < 0 || winRate > 1)
                throw new ArgumentException($"胜率{winRate:F6}必须在[0,1]范围内", nameof(winRate));
            
            if (currentCapital <= 0)
                throw new ArgumentException("当前资金必须大于0", nameof(currentCapital));
            
            if (maxCapital <= currentCapital)
                throw new ArgumentException("最大资金必须大于当前资金", nameof(maxCapital));

            double p = winRate;
            double q = 1 - winRate;
            
            // 处理边界条件
            if (p == 0) return 1.0; // 胜率为0，必然破产
            if (p == 1) return 0.0; // 胜率为1，不会破产

            // 公平游戏情况 (p = q = 0.5)
            if (Math.Abs(p - 0.5) < CALCULATION_PRECISION)
            {
                return 1.0 - (double)currentCapital / maxCapital;
            }

            // 一般情况：不公平游戏
            double qOverP = q / p;
            double qOverPPowerA = Math.Pow(qOverP, currentCapital);
            double qOverPPowerN = Math.Pow(qOverP, maxCapital);
            
            if (Math.Abs(qOverPPowerN - 1.0) < CALCULATION_PRECISION)
            {
                // 避免除以零的近似情况
                return 1.0 - (double)currentCapital / maxCapital;
            }
            
            double bankruptcyProbability = (qOverPPowerA - qOverPPowerN) / (1.0 - qOverPPowerN);
            
            return Math.Max(0.0, Math.Min(1.0, bankruptcyProbability));
        }

        #endregion

        #region 动态杠杆调整方法

        /// <summary>
        /// 计算最优杠杆比例
        /// 基于期望收益率和波动率：L* = min(μ/(σ²) × 0.5, L_max)
        /// </summary>
        /// <param name="expectedReturn">期望收益率μ</param>
        /// <param name="volatility">波动率σ</param>
        /// <param name="maxLeverageLimit">杠杆上限</param>
        /// <returns>最优杠杆比例</returns>
        public double CalculateOptimalLeverage(double expectedReturn, double volatility, 
            double maxLeverageLimit = MAX_LEVERAGE_RATIO)
        {
            if (volatility <= 0)
                throw new ArgumentException("波动率必须大于0", nameof(volatility));
            
            if (expectedReturn <= 0)
            {
                // 负期望收益时使用最小杠杆
                return MIN_LEVERAGE_RATIO;
            }
            
            // Kelly-based杠杆计算：L* = μ/(σ²) × 0.5
            double kellyLeverage = (expectedReturn / (volatility * volatility)) * 0.5;
            
            // 应用边界约束
            double optimalLeverage = Math.Max(MIN_LEVERAGE_RATIO, 
                Math.Min(maxLeverageLimit, kellyLeverage));
            
            return Math.Round(optimalLeverage, 2);
        }

        /// <summary>
        /// 基于市场波动环境调整杠杆比例
        /// 低波动期(σ<0.01): 1:200杠杆
        /// 中波动期(0.01≤σ<0.02): 1:100杠杆  
        /// 高波动期(σ≥0.02): 1:50杠杆
        /// </summary>
        /// <param name="volatility">当前市场波动率</param>
        /// <param name="baseOptimalLeverage">基础最优杠杆</param>
        /// <returns>调整后的杠杆比例</returns>
        public double AdjustLeverageByVolatilityEnvironment(double volatility, double baseOptimalLeverage)
        {
            if (volatility < 0)
                throw new ArgumentException("波动率不能为负", nameof(volatility));
            
            double environmentLeverage;
            
            if (volatility < LOW_VOLATILITY_THRESHOLD)
            {
                // 低波动期：使用较高杠杆
                environmentLeverage = 200.0;
            }
            else if (volatility < MEDIUM_VOLATILITY_THRESHOLD)
            {
                // 中波动期：使用中等杠杆
                environmentLeverage = 100.0;
            }
            else
            {
                // 高波动期：使用较低杠杆
                environmentLeverage = 50.0;
            }
            
            // 取基础最优杠杆和环境调整杠杆的较小值
            return Math.Min(baseOptimalLeverage, environmentLeverage);
        }

        /// <summary>
        /// 基于破产概率约束调整杠杆上限
        /// 确保破产概率不超过目标阈值（5%）
        /// </summary>
        /// <param name="expectedReturn">期望收益率</param>
        /// <param name="volatility">波动率</param>
        /// <param name="maxAllowedProbability">最大允许破产概率</param>
        /// <returns>杠杆上限</returns>
        public double CalculateLeverageLimit(double expectedReturn, double volatility, 
            double maxAllowedProbability = TARGET_BANKRUPTCY_PROBABILITY)
        {
            if (volatility <= 0)
                throw new ArgumentException("波动率必须大于0", nameof(volatility));
            
            if (maxAllowedProbability <= 0 || maxAllowedProbability >= 1)
                throw new ArgumentException("破产概率必须在(0,1)范围内", nameof(maxAllowedProbability));
            
            // 二分搜索寻找满足破产概率约束的最大杠杆
            double minLeverage = MIN_LEVERAGE_RATIO;
            double maxLeverage = MAX_LEVERAGE_RATIO;
            double tolerance = 0.1; // 杠杆精度
            
            while (maxLeverage - minLeverage > tolerance)
            {
                double testLeverage = (minLeverage + maxLeverage) / 2.0;
                double bankruptcyProb = CalculateContinuousBankruptcyProbability(
                    expectedReturn, volatility, testLeverage);
                
                if (bankruptcyProb <= maxAllowedProbability)
                {
                    minLeverage = testLeverage; // 可以使用更高杠杆
                }
                else
                {
                    maxLeverage = testLeverage; // 需要降低杠杆
                }
            }
            
            return Math.Round(minLeverage, 1);
        }

        #endregion

        #region 综合评估和建议方法

        /// <summary>
        /// 计算风险调整收益指标
        /// 目标函数：max E[log(终端财富)] - λ × P(破产)
        /// </summary>
        /// <param name="expectedLogReturn">期望对数收益</param>
        /// <param name="bankruptcyProbability">破产概率</param>
        /// <param name="riskAversion">风险厌恶参数λ</param>
        /// <returns>风险调整收益</returns>
        public double CalculateRiskAdjustedReturn(double expectedLogReturn, double bankruptcyProbability, 
            double riskAversion = RISK_AVERSION_PARAMETER)
        {
            return expectedLogReturn - riskAversion * bankruptcyProbability;
        }

        /// <summary>
        /// 获取杠杆调整建议
        /// </summary>
        /// <param name="expectedReturn">期望收益率</param>
        /// <param name="volatility">波动率</param>
        /// <param name="currentLeverage">当前杠杆</param>
        /// <returns>杠杆调整建议</returns>
        public LeverageAdjustmentAdvice GetLeverageAdjustmentAdvice(double expectedReturn, 
            double volatility, double currentLeverage)
        {
            var advice = new LeverageAdjustmentAdvice
            {
                CurrentLeverage = currentLeverage,
                MarketVolatility = volatility,
                ExpectedReturn = expectedReturn
            };
            
            // 计算最优杠杆
            advice.OptimalLeverage = CalculateOptimalLeverage(expectedReturn, volatility);
            
            // 环境调整
            advice.EnvironmentAdjustedLeverage = AdjustLeverageByVolatilityEnvironment(
                volatility, advice.OptimalLeverage);
            
            // 风险约束
            advice.RiskConstrainedLeverage = CalculateLeverageLimit(expectedReturn, volatility);
            
            // 最终建议（取最严格的约束）
            advice.RecommendedLeverage = Math.Min(
                Math.Min(advice.OptimalLeverage, advice.EnvironmentAdjustedLeverage),
                advice.RiskConstrainedLeverage);
            
            // 计算当前和建议杠杆的破产概率
            advice.CurrentBankruptcyProbability = CalculateContinuousBankruptcyProbability(
                expectedReturn, volatility, currentLeverage);
            advice.RecommendedBankruptcyProbability = CalculateContinuousBankruptcyProbability(
                expectedReturn, volatility, advice.RecommendedLeverage);
            
            // 生成调整建议
            if (Math.Abs(advice.RecommendedLeverage - currentLeverage) < 1.0)
            {
                advice.AdjustmentAction = "保持当前杠杆";
            }
            else if (advice.RecommendedLeverage > currentLeverage)
            {
                advice.AdjustmentAction = $"建议增加杠杆至{advice.RecommendedLeverage:F1}倍";
            }
            else
            {
                advice.AdjustmentAction = $"建议降低杠杆至{advice.RecommendedLeverage:F1}倍";
            }
            
            // 风险评级
            advice.RiskLevel = advice.RecommendedBankruptcyProbability switch
            {
                < 0.01 => "极低风险",
                < 0.03 => "低风险", 
                < 0.05 => "中等风险",
                < 0.10 => "高风险",
                _ => "极高风险"
            };
            
            return advice;
        }

        /// <summary>
        /// 验证杠杆设置的安全性
        /// </summary>
        /// <param name="leverageRatio">杠杆比例</param>
        /// <param name="expectedReturn">期望收益率</param>
        /// <param name="volatility">波动率</param>
        /// <returns>安全性验证结果</returns>
        public LeverageSafetyValidation ValidateLeverageSafety(double leverageRatio, 
            double expectedReturn, double volatility)
        {
            var validation = new LeverageSafetyValidation
            {
                LeverageRatio = leverageRatio,
                ExpectedReturn = expectedReturn,
                Volatility = volatility
            };
            
            // 计算破产概率
            validation.BankruptcyProbability = CalculateContinuousBankruptcyProbability(
                expectedReturn, volatility, leverageRatio);
            
            // 安全性评估
            validation.IsSafe = validation.BankruptcyProbability <= TARGET_BANKRUPTCY_PROBABILITY;
            validation.SafetyMargin = TARGET_BANKRUPTCY_PROBABILITY - validation.BankruptcyProbability;
            
            // 生成警告信息
            if (!validation.IsSafe)
            {
                validation.WarningMessage = $"警告：破产概率{validation.BankruptcyProbability:P2}超过目标阈值{TARGET_BANKRUPTCY_PROBABILITY:P2}";
            }
            else if (validation.SafetyMargin < 0.01)
            {
                validation.WarningMessage = $"注意：接近风险边界，安全边际仅{validation.SafetyMargin:P2}";
            }
            else
            {
                validation.WarningMessage = $"安全：破产概率{validation.BankruptcyProbability:P2}，安全边际{validation.SafetyMargin:P2}";
            }
            
            return validation;
        }

        #endregion
    }

    #region 数据结构定义

    /// <summary>
    /// 杠杆调整建议数据结构
    /// </summary>
    public class LeverageAdjustmentAdvice
    {
        public double CurrentLeverage { get; set; }
        public double OptimalLeverage { get; set; }
        public double EnvironmentAdjustedLeverage { get; set; }
        public double RiskConstrainedLeverage { get; set; }
        public double RecommendedLeverage { get; set; }
        public double MarketVolatility { get; set; }
        public double ExpectedReturn { get; set; }
        public double CurrentBankruptcyProbability { get; set; }
        public double RecommendedBankruptcyProbability { get; set; }
        public string AdjustmentAction { get; set; } = "";
        public string RiskLevel { get; set; } = "";
    }

    /// <summary>
    /// 杠杆安全性验证结果
    /// </summary>
    public class LeverageSafetyValidation
    {
        public double LeverageRatio { get; set; }
        public double ExpectedReturn { get; set; }
        public double Volatility { get; set; }
        public double BankruptcyProbability { get; set; }
        public bool IsSafe { get; set; }
        public double SafetyMargin { get; set; }
        public string WarningMessage { get; set; } = "";
    }

    #endregion
}
